#ifndef _SIMPLE_H_
#define _SIMPLE_H_ 1
#include<array>
#include<iostream>
namespace Locale{    
    /**
     * @brief low effective collector for address collecting
     * free all the pointers when the object destructive function called
    */
    class list_gc final{
        private:
            static constexpr size_t STACKSIZE = 4000;
            std::array<void*,STACKSIZE> addr;
            size_t pos;// show the next postition to insert
        public:
            ~list_gc();
            list_gc()noexcept:pos(0){addr.fill(nullptr);};
            /**
             * @brief disable the copy constructor
            */
            template<size_t __size>
                list_gc(std::array<void*,__size>const&)=delete;
            /**
             * @brief append the address of new allocated
             * if the pos is the MAX
             * shrink the list then try again
            */
            list_gc& push(void* nd);
            /**
             * @brief shrink the list to nested
            */
            void shrink()noexcept;
            /**
             * @brief free the existed one
             * if not existed, nothing occur
            */
            bool del(void* nd){return find(nd,true);}
            /**
             * @brief find whether the addr exists
             * provide the option for deleting the address
            */
            bool find(void* nd,bool Del=false)noexcept;
            /**
             * @brief delete the address by index
            */
            bool erase(size_t index)noexcept;
            bool only()noexcept;
            bool empty()noexcept;
            /**
             * @brief clear this list
            */
            void clear()noexcept;
            friend std::ostream& operator<<(std::ostream&,list_gc const&);
    };
}
Locale::list_gc collector;//declare a list for management
//--------------overload operator new/new[] and delete/delete[]------------//
/**
 * @brief test allocate function for valgrind
 * @param arg new operator like function for simple TYPE
*/
template<typename T>
T* alloc(T const& arg){
    size_t size=sizeof(T);
    void* add=(T*)(size==0?malloc(1):malloc(size));
    if(add==NULL||add==nullptr)
        throw;
    collector.push(add);   
    *((T*)add)=arg;
    return (T*)add;
}
/**
 * @brief test allocate function for valgrind
 * just memory allocator for intricate TYPE
*/
template<typename T>
typename std::decay<T>::type* alloc(){
    size_t size=sizeof(T);
    using type=typename std::decay<T>::type;
    void* add=(size==0?malloc(1):malloc(size));
    if(add==NULL||add==nullptr)
        throw;
    collector.push(add);   
    return (type*)add;
}
/**
 * @brief overload operator new to make sure every allocated memory is traced
*/
void* operator new(size_t size){
    void* add=(size==0?malloc(1):malloc(size));
    if(add==NULL||add==nullptr)
        throw;
    collector.push(add);   
    return add;
}
/**
 * @brief overload operator delete to manager the local collector
*/
void operator delete(void* vp){
    collector.del(vp);
}

/**
 * @brief overload operator new[] to make sure every allocated memory is traced
*/
void* operator new[](size_t size){
    void* add=(size==0?malloc(1):malloc(size));
    if(add==NULL||add==nullptr)
        throw;
    collector.push(add);   
    return add;
}
/**
 * @brief overload operator delete[] to manager the local collector
*/
void operator delete[](void* vp){
    collector.del(vp);
}
namespace Locale{
    //------------implement part-----------------------------//
    /**
     * @brief show the pointers contained
    */
    std::ostream& operator<<(std::ostream&os,list_gc const&lg){
        for(int i=0;i<lg.pos;++i){
            if(lg.addr[i]==nullptr)
                os<<"nullptr"<<' ';
            else
                os<<lg.addr[i]<<' ';
        }
        return os;
    }
    template<typename T>
        void Exch(T& l,T& r){
            T shift=l;
            *l = *r;
            *r=*shift;
        }
    list_gc& list_gc::push(void* nd){
        if(pos==STACKSIZE-1)
            shrink();
        if(pos==STACKSIZE-1)
            throw std::out_of_range("stack overflow!");
        addr[pos]=nd;
        ++pos;
    }
    void list_gc::shrink()noexcept{
        auto begin=0;
        auto end=pos;
        while(addr[end]==nullptr&&end!=begin)
                --end;
        while(begin!=end){
            if(addr[begin]==nullptr){
                while(addr[end]==nullptr){
                    --end;
                    if(end==begin)
                        goto ShrinkEnd;
                }
                addr[begin]=addr[end];
                addr[end]=nullptr;
            }++begin;
        }
        ShrinkEnd:
        pos=begin+(addr[begin]==nullptr?0:1);
    }
    bool list_gc::erase(size_t index)noexcept{
        if(index>=pos||addr[index]==nullptr)return false;
        free(addr[index]);
        addr[index]=nullptr;
        return true;
    }
    bool list_gc::find(void* nd,bool Del)noexcept{
        for(int i=0;i<pos;++i){
            if(addr[i]==nd){
                if(Del){
                    erase(i);
                }
                return true;
            }
        }return false;
    }
    bool list_gc::only()noexcept{
        shrink();
        return addr[0]!=nullptr&&addr[1]==nullptr;
    }
    bool list_gc::empty()noexcept{
        shrink();
        return addr[0]==nullptr;
    }
    void list_gc::clear()noexcept{
        if(this->empty())return;
        for(int i=pos-1;i>=0;--i){
            if(addr[i]!=nullptr)
                erase(i);
        }
    }
    list_gc::~list_gc(){
        clear();
    }
}
#endif//_SIMPLE_H_